package com.viu.technology.service.user;

import com.alibaba.fastjson.JSONObject;
import com.viu.technology.constant.RedisKeyEnum;
import com.viu.technology.context.TokenContextHolder;
import com.viu.technology.dao.role.RoleDao;
import com.viu.technology.dao.user.UserDao;
import com.viu.technology.po.Role;
import com.viu.technology.po.User;
import com.viu.technology.util.JsonUtil;
import com.viu.technology.util.JwtTokenUtil;
import com.viu.technology.util.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserService userService;



    //unless不缓存空值
    //@Cacheable(cacheNames = "user:info",key = "#id",unless="#result == null")

    public User getUserAndRoleById(String id) {
        String suf = TokenContextHolder.getCachePrefix();
        String redisKey = RedisKeyEnum.REDIS_USER_KEY.getKey() + suf;
        User user = null;
        String userJson = (String) redisTemplate.opsForHash().get(redisKey, id);
        if (null!=userJson) {
            user = JSONObject.parseObject(userJson, User.class);
        } else {
            user = userDao.selUserAndRoleById(id);
            if (null != user) {
                userService.insertUserInfoToCache(suf, user);
            }
        }
        return user;
    }

    @Override
    public User getUserAndRoleByPhone(String phone) {
        User user = userDao.selUserAndRoleByPhone(phone);
        return user;
    }

    @Override
    public User getUserInfoById(String id) {
        return userDao.selectByPrimaryKey(id);
    }

    public User registerUser(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        User userRes = userDao.insertUser(user);
        Role roleRes = roleDao.insertRole(new Role("普通群众", user.getId()));
        List list = new ArrayList();
        list.add(roleRes);

        if (null != userRes && null != roleRes) {
            userRes.setRoles(list);
            return user;
        }

        //调用Spring监听器
        //applicationContext.publishEvent(new UserRegisterEvent(new StandardContext(), user));

        return null;
    }

    public String login(String phone, String password) {
        //将用户名和密码生成Token
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(phone, password);
        //调用该方法时SpringSecurity会去调用JwtUserDetailsServiceImpl 进行验证
        Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        User userDetails = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return JwtTokenUtil.generateToken(userDetails);
    }

    //@Transactional
    @Override
    public User insertUserInfoToCache(String suffix,User user) {
        JSONObject userJson = JsonUtil.objectToJsonObject(user);
        String redisKey = RedisKeyEnum.REDIS_USER_KEY.getKey()+ suffix;
        //redisTemplate.opsForHash().put(redisKey, user.getId(), JsonUtil.objectToString(user));
        if (redisTemplate.hasKey(redisKey)) {
            redisTemplate.opsForHash().put(redisKey, user.getId(), JsonUtil.objectToString(user));
        } else {
            redisTemplate.opsForHash().put(redisKey, user.getId(), JsonUtil.objectToString(user));
            redisTemplate.expire(redisKey, 7, TimeUnit.DAYS);
        }

        return user;
    }

    /*private ServletContainerInitializer getServletContextInitializer(String contextPath) {
        return (c, context) -> {
            Servlet servlet = new GenericServlet() {

                @Override
                public void service(ServletRequest req, ServletResponse res)
                        throws ServletException, IOException {
                    ServletContext context = req.getServletContext()
                            .getContext(contextPath);
                    context.getRequestDispatcher("/cloudfoundryapplication").forward(req,
                            res);
                }

            };
            context.addServlet("cloudfoundry", servlet).addMapping("/*");
        };
    }*/
}


